package simple.array;

import java.util.Arrays;

/**
 * <a href="https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/">1005. K 次取反后最大化的数组和</a>
 * 给你一个整数数组 nums 和一个整数 k ，按以下方法修改该数组：
 * 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。
 * 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。
 * 以这种方式修改数组后，返回数组 可能的最大和 。
 * 示例 1：
 *   输入：nums = [4,2,3], k = 1
 *   输出：5
 *   解释：选择下标 1 ，nums 变为 [4,-2,3] 。
 * 示例 2：
 *   输入：nums = [3,-1,0,2], k = 3
 *   输出：6
 *   解释：选择下标 (1, 2, 2) ，nums 变为 [3,1,0,2] 。
 * 示例 3：
 *   输入：nums = [2,-3,-1,5,-4], k = 2
 *   输出：13
 *   解释：选择下标 (1, 4) ，nums 变为 [2,3,-1,5,4] 。
 * 提示：
 *   1 <= nums.length <= 10^4
 *   -100 <= nums[i] <= 100
 *   1 <= k <= 10^4
 * @author 刘学松
 * @date 2023-07-03 10:35
 */
public class K次取反后最大化的数组和 {
    public int largestSumAfterKNegations(int[] nums, int k) {
        Arrays.sort(nums);
        int sum = 0;
        int length = nums.length, i = 0;
        // 负数转正累加，直到k=0
        while (i < length && nums[i] < 0 && k > 0) {
            sum -= nums[i];
            ++i;
        }
        // 如果还剩奇数k，则要把最小值当做负数，减两次（包括前面已经加过的一次）
        if ((k & 1) == 1) {
            if (i == length) {
                // 如果遍历结束了，表示数组里都是负数，则减去最末尾的那个最大负数2次
                sum -= (-nums[length - 1] << 1);
            } else {
                // 遍历到i时遇到正数了，则取i-1和i位置上的最小正数，当做负数减2次
                int min = i == 0 ? nums[i] : Math.min(Math.abs(nums[i - 1]), nums[i]);
                sum -= (min << 1);
                // 剩余继续遍历累加
                while (i < length) {
                    sum += nums[i];
                    ++i;
                }
            }
        } else {
            // k为0了，剩余继续遍历累加
            while (i < length) {
                sum += nums[i];
                ++i;
            }
        }
        return sum;
    }
}
